import info.gridworld.actor.Actor;
import info.gridworld.actor.ActorWorld;
import info.gridworld.grid.Location;
import info.gridworld.grid.UnboundedGrid;

import java.util.ArrayList;


/**
 * This class creates a new World in which Game of Life Cells function. Beyond the inherited ActorWorld functions,
 * it keeps track of the current generation and the current number of live Cells in the Grid. Additionally, it modifies
 * the default mouse behavior to hide the GridWorld tooltips and Constructor/Properties menu, instead simply adding or
 * removing Cells from the Grid based on Location clicked.
 * 
 * @author Drew Gallagher
 * @version 1.0
 * @see ActorWorld
 */
public class LifeWorld extends ActorWorld {
	
	/**
	 * The first line of the information message.
	 * 
	 * @since 1.0
	 */
	private static final String FIRST_LINE = "Welcome to Conway's Game of Life." +
			"Choose \"Run\" or click the grid to modify Cells.\n";
	
	
	
	/**
	 * A measure of the current generation. Increased by 0.5 each step, and then cast to an <code>int</code> value
	 * to display the actual generation.
	 * 
	 * @since 1.0
	 */
	private double generation;
	
	

	/**
	 * Constructs a LifeWorld with default properties. A LifeWorld only uses an UnboundedGrid for accurate
	 * implementation of the Game of Life.
	 * 
	 * @since 1.0
	 * @see UnboundedGrid
	 */
	public LifeWorld() {
		this.setGrid(new UnboundedGrid<Actor>());
		this.generation = 0.0;
		System.setProperty("info.gridworld.gui.selection", "hide");
		System.setProperty("info.gridworld.gui.tooltips", "hide");
		System.setProperty("info.gridworld.gui.frametitle", "Conway's Game of Life  \u2014  GridWorld");
		this.updateMessage();
	} // End Constructor
	
	
	
	/**
	 * Updates the information message to include the current generation and live Cell population.
	 *
	 * @since 1.0
	 */
	private void updateMessage() {
		int live = this.getGrid().getOccupiedLocations().size();
		this.setMessage(FIRST_LINE + "Generation: "+ (int)this.generation + ", Live Cells: " + live);
	} // End void updateMessage
	
	
	
	/**
	 * Executes the Step function of ActorWorld and updates the generation and information message.
	 * 
	 * @since 1.0
	 * @see ActorWorld.#step()
	 */
	public void step() {
		super.step();
		this.generation += 0.5;
		this.updateMessage();
	} // End void step
	
	/**
	 * Manages the mouse behavior. If the Location clicked is empty, adds a new Cell at that location. If it is
	 * currently occupied by a Cell, it removes that Cell from the Grid.
	 * 
	 * @since 1.0
	 */
	public boolean locationClicked(Location loc) {
		if (this.getGrid().get(loc) == null) {
			new Cell().putSelfInGrid(this.getGrid(), loc);
		} else {
			this.getGrid().get(loc).removeSelfFromGrid();
		} // End If
		this.updateMessage();
		return true;
	} // End boolean locationClicked
	
	/**
	 * Adds a new Actor (Cell) at a random empty location in the Grid.
	 * 
	 * @since 1.0
	 * @see ActorWorld.#add(Actor)
	 */
	public void add(Actor actor) {
		super.add(actor);
		this.updateMessage();
	} // End void add
	
	/**
	 * Adds a new Actor (Cell) at the specified Location.
	 * 
	 * @since 1.0
	 * @see ActorWorld.#add(Location, Actor)
	 */
	public void add(Location loc, Actor actor) {
		super.add(loc, actor);
		this.updateMessage();
	} // End void add
	
	
	
	/**
	 * Adds a Cell Pattern to the grid.
	 * 
	 * @param locs ArrayList containing Pattern.
	 * @since 1.0
	 * @see Pattern
	 */
	public void addPattern(ArrayList<Location> locs) {
		for (Location loc : locs) {
			new Cell().putSelfInGrid(this.getGrid(), loc);
		} // End Loop
	} // End void addPattern
	
} // End class LifeWorld
